﻿using AgentSystem.AgentCreator.Sbpel;
using AgentSystem.AgentCreator.Util;
using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AgentCreator
{
    class Program
    {
        /// <summary>
        /// Agent File Path
        /// </summary>
        private static string agentFilePath;

        #region Flags set from Arguments

        /// <summary>
        /// Enables output of the agent code
        /// </summary>
        private static bool outputAgentCode = true;

        /// <summary>
        /// Enables compilation of the agent code
        /// </summary>
        private static bool compileAgentCode = false;

        /// <summary>
        /// Enable running the agent code
        /// </summary>
        private static bool runAgentCode = false;

        /// <summary>
        /// Flag for showing the help screen
        /// </summary>
        private static bool showHelpMessage = false;

        #endregion

        static void Main(string[] args)
        {
            ConsoleColor initialConsoleColor = Console.ForegroundColor;

            if ((args.Count() == 0) || (args.Count() == 1 && (args[0].Equals("-h") || args[0].Equals("-help"))))
            {
                showHelpMessage = true;
            }
            else
            {
                agentFilePath = args[0];
                GetFlags(args);
            }

            try
            {
                CodeCompileUnit compileUnit = null;
                CSharpCodeProvider codeProvider = new CSharpCodeProvider();
                
                if (showHelpMessage)
                {
                    HelpTemplate helpTemplate = new HelpTemplate();
                    string helpContent = helpTemplate.TransformText();
                    Console.WriteLine(helpContent);
                }
                else
                {
                    SbpelReader reader = new SbpelReader(agentFilePath);
                    IEnumerable<CodeObject> codeDom = reader.GetCodeDom();

                    CodeNamespaceImport[] namespacesToImport = new CodeNamespaceImport[] {
                        new CodeNamespaceImport("System"),
                        new CodeNamespaceImport("System.Threading"),
                        new CodeNamespaceImport("AgentSystem.AgentBaseFunctionality")
                    };

                    //Create the agent Namespace and add it to the compile unit
                    CodeNamespace agentNamespace = new CodeNamespace("Agents");
                    agentNamespace.Imports.AddRange(namespacesToImport);
                    compileUnit = new CodeCompileUnit();
                    compileUnit.Namespaces.Add(agentNamespace);


                    foreach (var typeDeclaration in codeDom)
                    {
                        agentNamespace.Types.Add(typeDeclaration as CodeTypeDeclaration);
                    }
                }

                //Output Agent Code
                if (outputAgentCode && !showHelpMessage)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    codeProvider.GenerateCodeFromCompileUnit(compileUnit, Console.Out, null);   
                }

                //Compile the code
                if (compileAgentCode && !showHelpMessage)
                {
                    string[] referencedAssemblies = { "System.Runtime.Serialization.dll", "System.Xml.dll", "AgentSystem.AgentBaseFunctionality.dll" };
                    string compilerErrors = string.Empty;


                    if (SimpleCodeCompiler.CompileCode(compileUnit, args[0], referencedAssemblies, true, ref compilerErrors))
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("Code successfully compiled!");
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine(compilerErrors);
                        Console.WriteLine("Compilation failed!");
                        
                    }
                }

                //Run the code
                if (runAgentCode && !showHelpMessage)
                {
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine("Starting agent...");

                    ProcessStartInfo agentStartInfo = new ProcessStartInfo(args[0] + ".exe");
                    agentStartInfo.Arguments = string.Join(" ", args.Skip(1).Where(p => p[0] != '-').ToArray());

                    Process.Start(agentStartInfo);
                }

            }
            catch (Exception exception)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(exception.Message);
            }

            Console.ForegroundColor = ConsoleColor.White;
        }

        /// <summary>
        /// Gets flags from Arguments.
        /// </summary>
        /// <param name="args">Arguments Array</param>
        private static void GetFlags(string[] args)
        {
            if (args.Count() > 1)
            {
                foreach (var item in args)
                {
                    switch (item)
                    {
                        case "-output-code":
                        case "-output":
                        case "-o":
                            outputAgentCode = true;
                            break;
                        case "-compile-code":
                        case "-compile":
                        case "-c":
                            compileAgentCode = true;
                            break;
                        case "-run-code":
                        case "-run":
                        case "-r":
                            compileAgentCode = true;
                            runAgentCode = true;
                            break;
                        case "-help":
                        case "-h":
                            showHelpMessage = true;
                            runAgentCode = false;
                            compileAgentCode = false;
                            outputAgentCode = false;
                            break;
                    }
                }
            }
        }
    }
}
